package main.Link;

import main.MainApp;
import main.SQL.MsSQLConnect;
import main.SQL.SQLRsrc;
import main.SQL.SQLTaskRsrc;
import main.Trees.ProjectNode;
import main.Trees.SmetNode;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;

public class LinkArray extends ArrayList<SQLLink>{
    private ArrayList<SQLLink> linkArray;
    private Connection connSql;
    private String dbName;
    private int projId;
    private Boolean filter;

    private ProjectNode curProject;
    private HashMap<String, SQLRsrc> rsrcs;

    private ArrayList<SQLTaskRsrc> updateRaList;

    public LinkArray(ProjectNode project) {
        this.dbName = project.getDbName();
        this.projId = project.getId();
        this.filter = false;
    }

    public ArrayList<SQLLink> getLinkArray() {
        return linkArray;
    }

    public ArrayList<SQLLink> getLinkArraySort(String from) {
        if (from.equals("task")) {
            Collections.sort(linkArray, new Comparator<SQLLink>() {
                @Override
                public int compare(SQLLink sqlLink, SQLLink sqlLink2) {
                    return sqlLink.getTaskShortName().compareTo(sqlLink2.getTaskShortName());
                }
            });
        } else {
            Collections.sort(linkArray, new Comparator<SQLLink>() {
                @Override
                public int compare(SQLLink sqlLink, SQLLink sqlLink2) {
                    int smrname = sqlLink.getSmNum().compareTo(sqlLink2.getSmNum());
                    if (smrname == 0) {
                        smrname = sqlLink.getSmrNum().compareTo(sqlLink2.getSmrNum());
                    }
                    return smrname;
                }
            });
        }

        return linkArray;
    }

    public void downloadFromSQL() {
        ArrayList<SQLLink> linkArrayList = new ArrayList<>();
        MainApp.linkSmrMap = new HashMap<>();

        connSql = MsSQLConnect.ConnectDB("Factage");
        try {

            CallableStatement stmt = connSql.prepareCall( "{call getLink(?, ?)}" );

            stmt.setString(1, dbName);
            stmt.setInt(2, projId);

            ResultSet rs = stmt.executeQuery();

            while (rs.next()) {
                if (rs.getString("task_code") == null) continue;
                SQLLink link = new SQLLink(rs.getInt("link_id"), "", rs.getString("task_code"), rs.getString("task_name"), rs.getString("smr_num"), rs.getString("smr_name"), rs.getDouble("smr_vol"), rs.getDouble("link_factor"), rs.getDouble("link_full_factor"), rs.getBoolean("pv_flag"), rs.getInt("task_id"), rs.getInt("smr_id"), rs.getString("sm_num"), rs.getDouble("pv_vol"), rs.getString("smr_unit"));
                link.setTVol(new BigDecimal(rs.getString("t_vol") == null ? "0" : rs.getString("t_vol")).setScale(6, RoundingMode.HALF_UP));
                link.setMrVol(new BigDecimal(rs.getString("mr_vol") == null ? "0" : rs.getString("mr_vol")).setScale(6, RoundingMode.HALF_UP));
                link.setMechVol(new BigDecimal(rs.getString("mech_vol") == null ? "0" : rs.getString("mech_vol")).setScale(6, RoundingMode.HALF_UP));
                link.setDbName(dbName);
                link.setProjectId(projId);
                link.setActualPv(new BigDecimal(rs.getDouble("actual_pv")).setScale(6, RoundingMode.HALF_UP));
                link.setIsImportFactage(rs.getString("importFactage") != null && rs.getString("importFactage").equals("true"));

                if (MainApp.linkSmrMap.containsKey(link.getSmrMapId())) {
                    MainApp.linkSmrMap.get(link.getSmrMapId()).put(link.getTaskId(), link);
                } else {
                    MainApp.linkSmrMap.put(link.getSmrMapId(), new HashMap<Integer, SQLLink>());
                    MainApp.linkSmrMap.get(link.getSmrMapId()).put(link.getTaskId(), link);
                }

                if (MainApp.taskMap != null && MainApp.taskMap.containsKey(link.getTaskId())) MainApp.taskMap.get(link.getTaskId()).getLinks().put(link.getSmrMapId(), link);
                if (MainApp.allSmrMap.containsKey(link.getSmrMapId())) MainApp.allSmrMap.get(link.getSmrMapId()).getLinks().add(link);

                linkArrayList.add(link);
            }

            rs.close();
            stmt.close();

            connSql.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        this.linkArray = linkArrayList;
    }

    public ArrayList<SQLLink> setTaskFilter (ArrayList<ProjectNode> tasks) {
        ArrayList<SQLLink> filtered = new ArrayList<> ();
        for (ProjectNode task : tasks) {
            for (SQLLink link : linkArray) {
                if (task.getId() == link.getTaskId()) {
                    filtered.add(link);
                    this.filter = true;
                }
            }
        }
        return filtered;
    }

    public Boolean getFilter() {
        return filter;
    }

    public void setFilter(Boolean filter) {
        this.filter = filter;
    }

    //region removeLinks(ArrayList<SQLLink> links) - удаление связей, по выделенным работам и сметным строкам
    public void removeLinks(ArrayList<SmetNode> smrList, ArrayList<ProjectNode> taskList) {

        this.curProject = MainApp.curProject;
        this.rsrcs = MainApp.rsrcMap;

        ArrayList<SQLLink> removeLinksList = new ArrayList<>();

        //region Создаем список связей на удаление по выбранным работам и сметным строкам
        for (SQLLink link : linkArray) {
            for (SmetNode smr : smrList) {
                for (ProjectNode task : taskList) {
                    if (link.getTaskId() == task.getId() && link.getSmrId() == smr.getId()) {
                        removeLinksList.add(link);
                        task.getLinks().remove(link.getSmrMapId());
                    }
                }
            }
        }
        //endregion

        //region Вычисляем новые значения коэффициента по связям
        for (SmetNode smr : smrList) {
            BigDecimal fact = new BigDecimal(0);
            for (SQLLink link : linkArray) {
                if (link.getSmrId() == smr.getId() && !removeLinksList.contains(link)) {
                    fact = fact.add(link.getFact());
                }
            }


            smr.setFactor(fact);
            smr.setSmetHighlight();
        }
        //endregion

        deleteActivityResources(taskList, removeLinksList);
        updateSQLAfterDelete(removeLinksList, taskList);

    }
    //endregion

    private void deleteActivityResources(ArrayList<ProjectNode> taskList, ArrayList<SQLLink> removeLinksList) {
        for (SQLLink link : removeLinksList) {
            linkArray.remove(link);
        }
        
        for (ProjectNode task : taskList) {

            updateRaList = new ArrayList<>();

            BigDecimal trPv, trMech, trMr, trT;
            trPv = new BigDecimal(0);
            trMech = new BigDecimal(0);
            trMr = new BigDecimal(0);
            trT = new BigDecimal(0);

            for (SQLLink link : linkArray) {
                if (link.getTaskId() != task.getId()) continue;

                trPv = trPv.add(link.getPvVol()).setScale(6, RoundingMode.UP);
                trMech = trMech.add(link.getMechVol()).setScale(6, RoundingMode.UP);
                trMr = trMr.add(link.getMrVol()).setScale(6, RoundingMode.UP);
                trT = trT.add(link.getTVol()).setScale(6, RoundingMode.UP);
            }

            task.getRsrc().clear();

            if (trPv.signum() == 1 && rsrcs.containsKey(task.getTaskCodeValue())) {
                SQLRsrc rsr = rsrcs.get(task.getTaskCodeValue());

                SQLTaskRsrc tr = new SQLTaskRsrc(0, task.getId(), rsr.getRsrcId(), 0, rsr.getRsrcName(), rsr.getRsrcType(), rsr.getRsrcShortName(), trPv.doubleValue(), "", curProject.getDbName(), curProject.getId());
                task.getRsrc().add(tr);
                task.setTaskUse("true");
                updateRaList.add(tr);
            }

            if (trMech.signum() == 1 && rsrcs.containsKey("MECH")) {
                SQLRsrc rsr = rsrcs.get("MECH");

                SQLTaskRsrc tr = new SQLTaskRsrc(0, task.getId(), rsr.getRsrcId(), 0, rsr.getRsrcName(), rsr.getRsrcType(), rsr.getRsrcShortName(), trMech.doubleValue(), "", curProject.getDbName(), curProject.getId());
                task.getRsrc().add(tr);
                task.setTaskUse("true");
                updateRaList.add(tr);
            }

            //region Выборка идентификатора для ресурса трудозатрат
            PVCode code = new PVCode();
            String rsrcShortName = code.getRsrcShortName(task.getTaskCodeValue());

            if (!rsrcShortName.equals("T") && curProject.getProjCode() != null) {
                rsrcShortName = rsrcShortName + "-" + curProject.getProjCode();
            }

            if (!rsrcs.containsKey(rsrcShortName)) rsrcShortName = "T";
            //endregion

            if (trT.signum() == 1 && rsrcs.containsKey(rsrcShortName)) {
                SQLRsrc rsr = rsrcs.get(rsrcShortName);

                SQLTaskRsrc tr = new SQLTaskRsrc(0, task.getId(), rsr.getRsrcId(), 0, rsr.getRsrcName(), rsr.getRsrcType(), rsr.getRsrcShortName(), trT.doubleValue(), "", curProject.getDbName(), curProject.getId());
                task.getRsrc().add(tr);
                task.setTaskUse("true");
                updateRaList.add(tr);
            }

            if (trMr.signum() == 1 && rsrcs.containsKey("MR")) {
                SQLRsrc rsr = rsrcs.get("MR");

                SQLTaskRsrc tr = new SQLTaskRsrc(0, task.getId(), rsr.getRsrcId(), 0, rsr.getRsrcName(), rsr.getRsrcType(), rsr.getRsrcShortName(), trMr.doubleValue(), "", curProject.getDbName(), curProject.getId());
                task.getRsrc().add(tr);
                task.setTaskUse("true");
                updateRaList.add(tr);
            }
        }
    }

    private void updateSQLAfterDelete(ArrayList<SQLLink> removeLinksList, ArrayList<ProjectNode> taskList) {
        try {
            connSql = MsSQLConnect.ConnectDB("Factage");

            CallableStatement stmt = connSql.prepareCall( "{call deleteLink(?)}" );

            for (SQLLink link : removeLinksList) {
                if (link == null) continue;
                stmt.setInt(1, link.getId());

                stmt.addBatch();
            }
            stmt.executeBatch();

            stmt = connSql.prepareCall("{call prepareBatchTaskRsrc(?, ?, ?)}");

            for (ProjectNode task : taskList) {
                stmt.setString(1, curProject.getDbName());
                stmt.setInt(2, curProject.getId());
                stmt.setInt(3, task.getId());
                stmt.addBatch();
            }
            stmt.executeBatch();

            stmt = connSql.prepareCall("{call updateBatchTaskRsrc(?, ?, ?, ?, ?)}");
            for (SQLTaskRsrc ra : updateRaList) {
                stmt.setString(1, dbName);
                stmt.setInt(2, curProject.getId());
                stmt.setInt(3, ra.getTaskId());
                stmt.setInt(4, ra.getRsrcId());
                stmt.setFloat(5, (float) ra.getPlannedUnits());
                stmt.addBatch();
            }
            stmt.executeBatch();

            stmt.close();

            connSql.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //region removeSelectedLinks(ArrayList<SQLLink> links) - удаление связей, по выделенным связям
    public void removeSelectedLinks(ArrayList<SmetNode> smrList, ArrayList<ProjectNode> taskList, ArrayList<SQLLink> selLinks) {

        this.curProject = MainApp.curProject;
        this.rsrcs = MainApp.rsrcMap;

        //region Вычисляем новые значения коэффициента по связям
        for (SmetNode smr : smrList) {
            BigDecimal fact = new BigDecimal(0);
            for (SQLLink link : linkArray) {
                if (link.getSmrId() == smr.getId() && !selLinks.contains(link)) {
                    fact = fact.add(link.getFact());
                }
            }
            smr.setFactor(fact);
            smr.setSmetHighlight();
        }
        //endregion

        deleteActivityResources(taskList, selLinks);
        updateSQLAfterDelete(selLinks, taskList);

    }
    //endregion

}
